package algorithm.util;

public class BigDouble implements Comparable {
	
	private BigInteger _integer;
	private int _dot;
	
	public BigDouble(String d) {
		
		int s_dot = d.indexOf(".");
		String _s = d;
		if (s_dot > -1) {
			_s = d.substring(0, s_dot) + d.substring(s_dot+1);
			this._dot = d.length() - 1 - s_dot;
		} else {
			this._dot = 0;
		}
		this._integer = new BigInteger(_s);
		this._regular();
	}
	
	public BigDouble(BigInteger integer, int dot) {
		this._integer = integer;
		this._dot = dot;
	}

	public BigDouble mul(BigDouble t) {

		BigDouble d = new BigDouble(this._integer.mul(t._integer), this._dot + t._dot);
		d._regular();
		return d;
	}
	
	public BigDouble pow(int n) {
		
		if (n == 0) {
			return new BigDouble(new BigInteger("1"), 0);
		} else if (n == 1) {
			return this;
		} else {
			BigDouble ret = this;
			for (int i = 1; i < n; i ++) {
				ret = ret.mul(this);
			}
			ret._regular();
			return ret;
		}
	}

	private void _regular() {

		String s = this._integer.toString();
		if ("0".equals(s)) {
			this._dot = 0;
		} else {
			int len = s.length();
			
			for (int i = len-1; i > len-1-this._dot && i > -1; i --) {
				if (s.charAt(i) != '0') {
					break;
				} else {
					s = s.substring(0, i);
					this._dot -= 1;
					continue;
				}
			}
			this._integer = new BigInteger(s); 
		}
	}
	
	
	@Override
	public String toString() {
		String s = this._integer.toString();
		if (this._dot < 1) {
			return s;
		} else {
			int len = s.length();
			if (this._dot > len) {
				for (int i = 0; i < this._dot-len; i ++) {
					s = "0" + s;
				}
				return "0." + s;
			} else {
				int idx = len-this._dot;
				String a = s.substring(0, idx);
				String b = s.substring(idx);
				while (b.length() > 0 && b.charAt(b.length()-1) == '0') {
					b = b.substring(0, b.length()-1);
				}
				if (b.length() == 0) {
					return a;
				} else {
					return a + "." + b;
				}
			}
		}
	}

	public int compareTo(Object obj) {
		
		if (obj == null || !BigDouble.class.isAssignableFrom(obj.getClass())) {
			throw new RuntimeException("Wrong Number!");
		} else {
			BigDouble d = (BigDouble)obj;
			int delta = -1;
			String x = this._integer.toString();
			String y = d._integer.toString();
			if (d._dot > this._dot) {
				delta = d._dot - this._dot;
				for (int i = 0; i < delta; i ++) {
					x += "0";
				}
			} else {
				delta = this._dot - d._dot;
				for (int i = 0; i < delta; i ++) {
					y += "0";
				}
			}
			int[] _x = this._str2num(x);
			int[] _y = this._str2num(y);
			return this._compare(_x, _y);
		}
	}

	private int _compare(int[] x, int[] y) {
		
		if (x.length < y.length) {
			return -1;
		} else if (x.length > y.length) {
			return 1;
		} else {
			for (int i = x.length-1; i > -1; i --) {
				if (x[i] > y[i]) {
					return 1;
				} else if (x[i] < y[i]) {
					return -1;
				}
			}
			return 0;
		}
	}
	
	private int[] _str2num(String s) {

		if (s == null || s.trim().length() == 0) {
			return null;
		} else {
			s = s.trim();
			int len = s.length();
			int[] n = new int[len];
			for (int i = 0; i < len; i ++) {
				n[i] = Integer.valueOf(s.substring(len-i-1, len-i));
			}
			return n;
		}
	}
}
